package com.wpf.system.common.config;

import com.wpf.system.security.filter.AuthenticationFilter;
import com.wpf.system.security.handler.*;
import com.wpf.system.service.impl.UserDetailServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig{
    @Resource
    private UserDetailServiceImpl userDetailService;
    @Resource
    private LoginSuccessHandler loginSuccessHandler;
    @Resource
    private LoginFailureHandler loginFailureHandler;
    @Resource
    private CustomizeAuthenticationEntryPoint customizeAuthenticationEntryPoint;
    @Resource
    private CustomAccessDeineHandler customAccessDeineHandler;
    @Resource
    private AuthenticationFilter authenticationFilter;

    @Resource
    private LogoutHandler logoutHandler;

    @Bean
    public PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}

    private static final String[] URL_WHITELIST = {
            "/api/user/login",
            "/api/user/forgetPWD",
            "/api/user/restPW",
            "/api/captcha/code",
            "/api/captcha/emailCode",
            "/api/captcha/checkEmailCode",
    };

    // 资源权限
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http
                // 禁用csrf防御机制(跨域请求伪造)
                .csrf().disable()
                .cors()
                .and()
                // 登录配置
                .formLogin()
                //　自定义的登录请求的路径
                .loginProcessingUrl("/api/user/login")
                .successHandler(loginSuccessHandler)
                .failureHandler(loginFailureHandler)
                // 注销配置
                .and()
                .logout()
                .logoutUrl("/api/user/logout")
                .logoutSuccessHandler(logoutHandler)
                // 禁用Session
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 配置拦截器
                .and()
                .authorizeRequests()
                .antMatchers("/upload/**").permitAll()
                .antMatchers(URL_WHITELIST).anonymous()
                .anyRequest().authenticated()
                .and()
                .headers().frameOptions().disable()
                // 异常处理器
                .and()
                .exceptionHandling()
                // 匿名用户访问资源时处理器
                .authenticationEntryPoint(customizeAuthenticationEntryPoint)
                // 无权限访问处理器
                .accessDeniedHandler(customAccessDeineHandler)
                .and()
                // 配置自定义过滤器
                .addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class)
        ;
        return http.build();
    }

    // 配置认证处理器
    @Bean
    AuthenticationManager authenticationManager(HttpSecurity httpSecurity) throws Exception {
        AuthenticationManager authenticationManager = httpSecurity.getSharedObject(AuthenticationManagerBuilder.class)
                .userDetailsService(userDetailService)
                .passwordEncoder(passwordEncoder())
                .and()
                .build();
        return authenticationManager;
    }

}
